package com.example.oa.service;

import com.example.oa.dto.ApproveApprovalProcessDTO;
import com.example.oa.dto.CreateApprovalProcessDTO;
import com.example.oa.dto.QueryApprovalProcessDTO;
import com.example.oa.dto.SubmitApprovalProcessDTO;
import com.example.oa.entity.ApprovalProcessDO;
import com.example.oa.exception.BusinessException;
import com.example.oa.mapper.ApprovalProcessMapper;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

/**
 * <p>
 * OA流程流转Service测试类
 * </p>
 * @author 34448
 */
public class ApprovalProcessServiceTest {

    @Mock
    private ApprovalProcessMapper approvalProcessMapper;

    @InjectMocks
    private ApprovalProcessServiceImpl approvalProcessService;

    @BeforeEach
    public void setUp() {
        MockitoAnnotations.openMocks(this);
    }

    @Test
    public void testCreateApprovalProcess_Success() {
        CreateApprovalProcessDTO createDTO = new CreateApprovalProcessDTO();
        createDTO.setProcessName("Test Process");
        createDTO.setSubmitterId(1);
        createDTO.setApproverId(2);

        when(approvalProcessMapper.selectOne(any())).thenReturn(null);
        when(approvalProcessMapper.insert(any())).thenReturn(1);

        Boolean result = approvalProcessService.createApprovalProcess(createDTO);
        assertTrue(result);
        verify(approvalProcessMapper).selectOne(any());
        verify(approvalProcessMapper).insert(any());
    }

    @Test
    public void testCreateApprovalProcess_Failure() {
        CreateApprovalProcessDTO createDTO = new CreateApprovalProcessDTO();
        createDTO.setProcessName("Existing Process");
        createDTO.setSubmitterId(1);
        createDTO.setApproverId(2);

        ApprovalProcessDO existingProcess = new ApprovalProcessDO();
        existingProcess.setProcessId(1);
        existingProcess.setProcessName("Existing Process");

        when(approvalProcessMapper.selectOne(any())).thenReturn(existingProcess);

        assertThrows(BusinessException.class, () -> approvalProcessService.createApprovalProcess(createDTO));
        verify(approvalProcessMapper).selectOne(any());
        verify(approvalProcessMapper, never()).insert(any());
    }

    @Test
    public void testSubmitApprovalProcess_Success() {
        SubmitApprovalProcessDTO submitDTO = new SubmitApprovalProcessDTO();
        submitDTO.setProcessId(1);

        ApprovalProcessDO processDO = new ApprovalProcessDO();
        processDO.setProcessId(1);
        processDO.setStatus("Created");

        when(approvalProcessMapper.selectById(anyInt())).thenReturn(processDO);
        when(approvalProcessMapper.updateById(any())).thenReturn(1);

        Boolean result = approvalProcessService.submitApprovalProcess(submitDTO);
        assertTrue(result);
        verify(approvalProcessMapper).selectById(anyInt());
        verify(approvalProcessMapper).updateById(any());
    }

    @Test
    public void testSubmitApprovalProcess_Failure() {
        SubmitApprovalProcessDTO submitDTO = new SubmitApprovalProcessDTO();
        submitDTO.setProcessId(1);

        when(approvalProcessMapper.selectById(anyInt())).thenReturn(null);

        assertThrows(BusinessException.class, () -> approvalProcessService.submitApprovalProcess(submitDTO));
        verify(approvalProcessMapper).selectById(anyInt());
        verify(approvalProcessMapper, never()).updateById(any());
    }

    @Test
    public void testApproveApprovalProcess_Success() {
        ApproveApprovalProcessDTO approveDTO = new ApproveApprovalProcessDTO();
        approveDTO.setProcessId(1);
        approveDTO.setStatus("Approved");
        approveDTO.setComments("Approved by Admin");

        ApprovalProcessDO processDO = new ApprovalProcessDO();
        processDO.setProcessId(1);
        processDO.setStatus("Submitted");

        when(approvalProcessMapper.selectById(anyInt())).thenReturn(processDO);
        when(approvalProcessMapper.updateById(any())).thenReturn(1);

        Boolean result = approvalProcessService.approveApprovalProcess(approveDTO);
        assertTrue(result);
        verify(approvalProcessMapper).selectById(anyInt());
        verify(approvalProcessMapper).updateById(any());
    }

    @Test
    public void testApproveApprovalProcess_Failure() {
        ApproveApprovalProcessDTO approveDTO = new ApproveApprovalProcessDTO();
        approveDTO.setProcessId(1);
        approveDTO.setStatus("Approved");
        approveDTO.setComments("Approved by Admin");

        when(approvalProcessMapper.selectById(anyInt())).thenReturn(null);

        assertThrows(BusinessException.class, () -> approvalProcessService.approveApprovalProcess(approveDTO));
        verify(approvalProcessMapper).selectById(anyInt());
        verify(approvalProcessMapper, never()).updateById(any());
    }

    @Test
    public void testQueryApprovalProcesses_Success() {
        QueryApprovalProcessDTO queryDTO = new QueryApprovalProcessDTO();
        queryDTO.setProcessId(1);

        ApprovalProcessDO processDO = new ApprovalProcessDO();
        processDO.setProcessId(1);
        processDO.setProcessName("Test Process");

        when(approvalProcessMapper.selectList(any())).thenReturn(Arrays.asList(processDO));

        List<ApprovalProcessDO> result = approvalProcessService.queryApprovalProcesses(queryDTO);
        assertEquals(1, result.size());
        verify(approvalProcessMapper).selectList(any());
    }

    @Test
    public void testQueryApprovalProcesses_All_Success() {
        QueryApprovalProcessDTO queryDTO = new QueryApprovalProcessDTO();

        ApprovalProcessDO processDO = new ApprovalProcessDO();
        processDO.setProcessId(1);
        processDO.setProcessName("Test Process");

        when(approvalProcessMapper.selectList(any())).thenReturn(Arrays.asList(processDO));

        List<ApprovalProcessDO> result = approvalProcessService.queryApprovalProcesses(queryDTO);
        assertEquals(1, result.size());
        verify(approvalProcessMapper).selectList(any());
    }

    @Test
    public void testQueryApprovalProcesses_Failure() {
        QueryApprovalProcessDTO queryDTO = new QueryApprovalProcessDTO();
        queryDTO.setProcessId(1);

        when(approvalProcessMapper.selectList(any())).thenReturn(Arrays.asList());

        assertThrows(BusinessException.class, () -> approvalProcessService.queryApprovalProcesses(queryDTO));
        verify(approvalProcessMapper).selectList(any());
    }

    @Test
    public void testDeleteApprovalProcess_Success() {
        Integer processId = 1;

        ApprovalProcessDO processDO = new ApprovalProcessDO();
        processDO.setProcessId(processId);

        when(approvalProcessMapper.selectById(anyInt())).thenReturn(processDO);
        when(approvalProcessMapper.deleteById(anyInt())).thenReturn(1);

        Boolean result = approvalProcessService.deleteApprovalProcess(processId);
        assertTrue(result);
        verify(approvalProcessMapper).selectById(anyInt());
        verify(approvalProcessMapper).deleteById(anyInt());
    }

    @Test
    public void testDeleteApprovalProcess_Failure() {
        Integer processId = 1;

        when(approvalProcessMapper.selectById(anyInt())).thenReturn(null);

        assertThrows(BusinessException.class, () -> approvalProcessService.deleteApprovalProcess(processId));
        verify(approvalProcessMapper).selectById(anyInt());
        verify(approvalProcessMapper, never()).deleteById(anyInt());
    }
}